import { UserLoginService } from '@/service'
import { ConfigService } from '@donews/nestjs-config'
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, Inject, forwardRef } from '@nestjs/common'
import { Reflector } from '@nestjs/core'
import { CoreException } from '..'
import { CoreExceptionType } from '../exception'
import { NRedis } from '../redis'
import { RType } from '../redis/interface'

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(
        private readonly reflector: Reflector,
        private readonly redis: NRedis,
        private readonly config: ConfigService,
        private readonly userLoginService: UserLoginService,
    ) {}
    public async canActivate(context: ExecutionContext): Promise<boolean> {
        const request = context.switchToHttp().getRequest()
        const auths = this.reflector.get<string[]>('auth', context.getHandler())
        let authorization = request.headers['authorization']
        if (auths) {
            if (!authorization && !request.headers?.devid)
                throw new CoreException(CoreExceptionType.ERROR_CORE_LOGIN_DEVID_FAIL)
            const ttl = this.config.get('login.ttl', 60 * 60)
            if (authorization) {
                request.user = await this.redis.get(RType.PREFIX_TOKEN + authorization)
            } else if (request.headers?.devid) {
                const newToken = await this.userLoginService.getToken(request.headers.devid, authorization)
                authorization = newToken.token
                request.user = newToken.user
            }
            if (!request.user) throw new CoreException(CoreExceptionType.ERROR_CORE_LOGIN_TOKEN_FAIL)
            await this.redis.set(RType.PREFIX_TOKEN + authorization, request.user, ttl)
        }
        request.authorization = authorization
        const roles = this.reflector.get<string[]>('roles', context.getHandler())
        return !roles || this.checkRoles(roles, request)
    }

    public checkRoles(roles: string[], request: any) {
        return roles.length > 0 && roles.includes(request?.user?.role?.roleid)
    }
}
